package secu;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.function.Consumer;

import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

/**
 * HMAC
 * HMAC是密钥相关的哈希运算消息认证码（Hash-based Message Authentication Code）的缩写
 * 由H.Krawezyk，M.Bellare，R.Canetti于1996年提出
 * 并于1997年作为RFC2104被公布，并在IPSec和其他网络协议（如SSL）中得以广泛应用
 * 用途：
 * 在发送方和接收方共享机密密钥的前提下，HMAC 可用于确定通过不安全信道发送的消息是否已被篡改。
 * @author ben
 * @date 2021-09-26 22:33:15 CST
 */
public class TestHmac {

	public static Consumer<Object> cs = System.out::println;
	
	private static final String ENCODING = "utf-8";

	public static void main(String[] args) {
		try {
			test1("HmacSHA1");
			test1("HmacSHA256");
			test1("HmacSHA512");
		} catch (InvalidKeyException | UnsupportedEncodingException | NoSuchAlgorithmException e) {
			cs.accept("发生异常：e=" + e.getClass() + ", " + e.getMessage());
		}
	}

	/**
	 * 试验1
	 * @author ben
	 * @date 2021-09-26 22:35:04 CST
	 * @param alg 算法名
	 * @throws UnsupportedEncodingException 
	 * @throws NoSuchAlgorithmException 
	 * @throws InvalidKeyException 
	 */
	public static void test1(final String alg) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
		cs.accept("test1() start...alg=" + alg);
		
		final String ptext = "abc";
		final String pkey = "key";
		
		byte[] data = pkey.getBytes(ENCODING);
		
		// 构造秘钥：第二个为算法
		SecretKey sk = new SecretKeySpec(data, alg);
		
		// 生成一个Mac算法的mac对象
		Mac mac = Mac.getInstance(alg);
		cs.accept("mac=" + mac);
		cs.accept("mac=" + mac.getProvider());
		cs.accept("mac=" + mac.getAlgorithm());
		cs.accept("mac=" + mac.getMacLength());
		
		// 用给定秘钥初始化Mac对象
		mac.init(sk);
		
		byte[] pbyte = ptext.getBytes(ENCODING);
		
		// 完成Mac操作
		byte[] result = mac.doFinal(pbyte);
		
		outputByteArr(result);
		cs.accept("----\n");
	}
	
	private static void outputByteArr(byte[] arr) {
		cs.accept("输出byte[] arr：length=" + arr.length);
		for (int i=0; i<arr.length; i++) {
			System.out.print(arr[i] + " ");
		}
		cs.accept("");
		for (int i=0; i<arr.length; i++) {
			System.out.printf("%02x ", arr[i]);
		}
		cs.accept("");
		StringBuffer sb = new StringBuffer();
		for (int i=0; i<arr.length; i++) {
			sb.append(Integer.toHexString((0x000000FF & arr[i]) | 0xFFFFFF00).substring(6)).append(" ");
		}
		cs.accept(sb.toString());
	}
}
